﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace MyProxy.Entity
{
    internal class Proxy
    {
       
        private Socket clientSocket;

        //定义一个空间，存储来自客户端请求数据包
        readonly Encoding ASCII = Encoding.UTF8;
        //设定编码
        //Byte[] RecvBytes = new Byte[4096];
        //定义一个空间，存储Web服务器返回的数据
        internal Proxy()
        {
        }


        internal Proxy(Socket socket)
        {
            this.clientSocket = socket;
        }

        public void Run()
        {
            int i = Thread.CurrentThread.ManagedThreadId;
            try
            {
                string clientmessage = " ";
                //存放来自客户端的HTTP请求字符串
                //存放解析出地址请求信息
                byte[] read = new byte[clientSocket.Available];
                int bytes1 = ReadMessage(read, read.Length, clientSocket, ref clientmessage);
                if (bytes1 == 0)
                {
                    //Console.WriteLine("判定有问题" + clientmessage);
                    clientSocket.Close();
                    return;
                }
                IPEndPoint ipEndpoint = GetIP(clientmessage, i, out string way);
                Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //创建连接Web服务器端的Socket对象
                IPsocket.Connect(ipEndpoint);
                //Socket连Web接服务器
                if (!IPsocket.Connected)
                {
                    //Console.WriteLine($"-----------{ipEndpoint.Address}Socket连接失败-----------");
                    clientSocket.Close();
                    return;
                }
                if (way.Trim() == "CONNECT")
                {
                    SendMess(clientSocket, IPsocket, "HTTP/1.1 200 Connection Established\r\n\r\n",i);
                    clientSocket.Close();
                    IPsocket.Close();
                    return;
                }
          
                //解析出要访问的服务器地址  
                byte[] ByteGet = ASCII.GetBytes(clientmessage);
                //代理访问软件对服务器端传送HTTP请求命令
                IPsocket.Send(ByteGet, ByteGet.Length, 0);
                //代理访问软件接收来自Web服务器端的反馈信息
                byte[] RecvBytes = new byte[1024 * 8];
                int rBytes = 0;
                try
                {
                    do
                    {
                        while (IPsocket.Available > 0)
                        {
                            Array.Clear(RecvBytes, 0, RecvBytes.Length);
                            rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
                            clientSocket.Send(RecvBytes, rBytes, 0);
                        };
                        while (clientSocket.Available > 0)
                        {
                            Array.Clear(RecvBytes, 0, RecvBytes.Length);
                            rBytes = clientSocket.Receive(RecvBytes, RecvBytes.Length, 0);
                            IPsocket.Send(RecvBytes, rBytes, 0);
                        };
                        Thread.Sleep(500);
                    } while (true);
                }
                catch (Exception)
                {
                    //Console.WriteLine($"-----------{ipEndpoint.Address}Socket连接完毕-----------");
                    clientSocket.Close();
                    IPsocket.Close();
                    return;
                }
            }
            catch (Exception e)
            {
                //Console.WriteLine($"--------------主方法错误[{i}]:{e.Message}-------------------");
            }
        }

        public int ReadMessage(byte[] b,int length,Socket s,ref string str)
        {
            s.Receive(b, length, 0);
            str=ASCII.GetString(b);
            return length;
        }


        public IPEndPoint GetIP(string httpMessage,int i,out string way)
        {
            try
            {
                int index1 = httpMessage.IndexOf(' ');
                int index2 = httpMessage.IndexOf(' ', index1 + 1);
                if ((index1 == -1) || (index2 == -1))
                {
                    //Console.WriteLine($"没获取到客户端的请求地址[{i}]");
                }
                //获取ip时用的方式
                way = httpMessage.Substring(0, index1);
                //获取ip时用的地址
                string part1 = httpMessage.Substring(index1 + 1, index2 - index1 - 1);
                bool ishttps = Regex.IsMatch(part1, "https");
                string URL = Regex.Replace(part1, "^http.*//", "");
                var portstr = Regex.Match(URL, "(?<=:)\\d*").Value;
                URL = Regex.Replace(URL, ":\\d*", "");
                URL = Regex.Replace(URL, "/.*", "");
                int port;
                if (portstr.Length > 0)
                {
                    port = Convert.ToInt32(portstr);
                }
                else
                {
                    port = !ishttps ? 80 : 443;
                }
                //IPHostEntry iplist = Dns.GetHostEntry(URL);
                IPAddress[] iplist = Array.FindAll(
                Dns.GetHostEntry(URL).AddressList,
                a => a.AddressFamily == AddressFamily.InterNetwork);
                //Console.WriteLine($"获取ip时用的IP地址:{iplist[0].ToString()}[{i}]");
                return new IPEndPoint(iplist[0], port);
            }
            catch (Exception e)
            {
                throw new Exception($"获取IP地址失败:{e.Message}");
            }
        }


        public void SendMess(Socket sender,Socket accepter,string s,int i) {
            try
            {
                NetworkStream IPsocketStream = new NetworkStream(accepter, false);
                NetworkStream clientStream = new NetworkStream(sender, false);
                byte[] b = ASCII.GetBytes(s);
                clientStream.Write(b, 0, b.Length);
                byte[] bytes = new byte[2048];
                int num;
                do
                {
                    while (IPsocketStream.DataAvailable)
                    {
                        num = IPsocketStream.Read(bytes, 0, bytes.Length);
                        clientStream.Write(bytes, 0, num);
                    };
                    while (clientStream.DataAvailable)
                    {
                        num = clientStream.Read(bytes, 0, bytes.Length);
                        IPsocketStream.Write(bytes, 0, num);
                    };
                    Thread.Sleep(500);
                } while (true);
              
            }
            catch (Exception e)
            {
                throw new Exception($"转发:{e.Message}");
            }
        }

        public void SendSock(IAsyncResult ar)
        {
            SendEntity entity = (SendEntity)ar.AsyncState;
            entity.socket.Send(entity.buff, entity.buff.Length, 0);

        }

    

    }

    internal class SendEntity
    {
        public byte[] buff { get; set; }
        public Socket socket { get; set; }
    }

    
        
}
